﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using WebStudio.Framework.Core;

namespace WebStudio.Framework.Helper
{
    public class StreamHelper
    {
        // Fields
        private bool _IsReadActive;
        private bool _IsReadBuffered;
        private byte[] _LineBreak;
        private byte[] _LineBuffer;
        private int _MaxLineSize;
        private byte[] _ReadBuffer;
        private int _ReadBufferEndPos;
        private int _ReadBufferOffset;
        private Stream _Stream;

        // Methods
        public StreamHelper(Stream stream)
            : this(stream, 0x1000, true)
        {
        }

        public StreamHelper(Stream stream, int maxLineSize, bool isReadBuffered)
        {
            this._MaxLineSize = 0x1000;
            this._LineBreak = new byte[] { 13, 10 };
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if ((maxLineSize < 1) || (maxLineSize > 0x7d00))
            {
                throw new ArgumentException("参数： maxLineSize 值必须 >= 1 and <= 32000 ！");
            }
            this._IsReadBuffered = isReadBuffered;
            if (this._IsReadBuffered)
            {
                this._ReadBuffer = new byte[0x7d00];
            }
            this._Stream = stream;
            this._LineBuffer = new byte[maxLineSize];
            this._MaxLineSize = maxLineSize;
        }

        public void Read(Stream storeStream, int count)
        {
            if (storeStream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (count < 1)
            {
                throw new ArgumentException("参数： count 值必须 >= 1 ！");
            }
            lock (this)
            {
                if (this._IsReadActive)
                {
                    throw new InvalidOperationException("读取操作未结束, 不允许多次读取！");
                }
                this._IsReadActive = true;
            }
            try
            {
                byte[] buffer = new byte[0x7d00];
                int totalReadedCount = 0;
                int readedCount = 0;
                while (totalReadedCount < count)
                {
                    if (this._ReadBufferOffset < this._ReadBufferEndPos)
                    {
                        int countReadedFromBuffer = Math.Min((int)(this._ReadBufferEndPos - this._ReadBufferOffset), (int)(count - totalReadedCount));
                        Array.Copy(this._ReadBuffer, this._ReadBufferOffset, buffer, 0, countReadedFromBuffer);
                        this._ReadBufferOffset += countReadedFromBuffer;
                    }
                    else
                    {
                        readedCount = this._Stream.Read(buffer, 0, Math.Min(buffer.Length, count - totalReadedCount));
                    }
                    if (readedCount == 0)
                    {
                        throw new Exception("流中没有这么多的数据供读取， 读取提前结束！");
                    }
                    totalReadedCount += readedCount;
                    storeStream.Write(buffer, 0, readedCount);
                }
            }
            finally
            {
                this._IsReadActive = false;
            }
        }

        public int ReadAll(Stream storeStream, int maxSize)
        {
            return this.ReadAll(storeStream, maxSize, SizeExceededActionCode.ThrowException);
        }

        public int ReadAll(Stream storeStream, int maxSize, SizeExceededActionCode exceededAction)
        {
            int result;
            if (storeStream == null)
            {
                throw new ArgumentNullException("storeStream");
            }
            if (maxSize < 1)
            {
                throw new ArgumentException("参数： maxSize 值必须 >= 1 ！");
            }
            lock (this)
            {
                if (this._IsReadActive)
                {
                    throw new InvalidOperationException("读取操作未结束, 不允许多次读取！");
                }
                this._IsReadActive = true;
            }
            try
            {
                byte[] buffer = new byte[0x7d00];
                int totalReadedCount = 0;
                int readedCount = 0;
            Label_0059:
                if (this._ReadBufferOffset < this._ReadBufferEndPos)
                {
                    Array.Copy(this._LineBuffer, this._ReadBufferOffset, buffer, 0, this._ReadBufferEndPos - this._ReadBufferOffset);
                    this._ReadBufferOffset = 0;
                    this._ReadBufferEndPos = 0;
                }
                else
                {
                    readedCount = this._Stream.Read(buffer, 0, buffer.Length);
                }
                if (readedCount != 0)
                {
                    totalReadedCount += readedCount;
                    if (totalReadedCount > maxSize)
                    {
                        if (exceededAction == SizeExceededActionCode.ThrowException)
                        {
                            throw new Exception("数据大小超出最大允许值");
                        }
                    }
                    else
                    {
                        storeStream.Write(buffer, 0, readedCount);
                    }
                    goto Label_0059;
                }
                if (totalReadedCount > maxSize)
                {
                    throw new Exception("数据大小超出最大允许值");
                }
                result = totalReadedCount;
            }
            finally
            {
                this._IsReadActive = false;
            }
            return result;
        }

        public int ReadByte()
        {
            if (!this._IsReadBuffered)
            {
                return this._Stream.ReadByte();
            }
            if (this._ReadBufferOffset >= this._ReadBufferEndPos)
            {
                this._ReadBufferEndPos = this._Stream.Read(this._ReadBuffer, 0, 0x7d00);
                this._ReadBufferOffset = 0;
                if (this._ReadBufferEndPos == 0)
                {
                    return -1;
                }
            }
            this._ReadBufferOffset++;
            return this._ReadBuffer[this._ReadBufferOffset - 1];
        }

        public int ReadHeader(Stream storeStream, int maxSize, SizeExceededActionCode exceededAction)
        {
            int result;
            if (storeStream == null)
            {
                throw new ArgumentNullException("storeStream");
            }
            lock (this)
            {
                if (this._IsReadActive)
                {
                    throw new InvalidOperationException("读取操作未结束, 不允许多次读取！");
                }
                this._IsReadActive = true;
            }
            try
            {
                BufferedStream bufferedStoreStream = new BufferedStream(storeStream, 0x7d00);
                int totalReadedCount = 0;
                int readedCount = 0;
                int rawReadedCount = 0;
            Label_004D:
                do
                {
                    readedCount = this.ReadLineInternal(this._LineBuffer, SizeExceededActionCode.ThrowException, out rawReadedCount);
                    if (rawReadedCount == 0)
                    {
                        goto Label_009F;
                    }
                    totalReadedCount += rawReadedCount;
                    if (readedCount == 0)
                    {
                        goto Label_009F;
                    }
                    if (totalReadedCount <= maxSize)
                    {
                        goto Label_007A;
                    }
                }
                while (exceededAction != SizeExceededActionCode.ThrowException);
                throw new Exception("数据大小超出最大允许值");
            Label_007A:
                bufferedStoreStream.Write(this._LineBuffer, 0, readedCount);
                bufferedStoreStream.Write(this._LineBreak, 0, this._LineBreak.Length);
                goto Label_004D;
            Label_009F:
                bufferedStoreStream.Flush();
                if (totalReadedCount > maxSize)
                {
                    throw new Exception("数据大小超出最大允许值");
                }
                result = totalReadedCount;
            }
            finally
            {
                this._IsReadActive = false;
            }
            return result;
        }

        public string ReadLine(Encoding encoding)
        {
            return this.ReadLine(encoding, SizeExceededActionCode.ThrowException);
        }

        public int ReadLine(byte[] buffer)
        {
            return this.ReadLine(buffer, SizeExceededActionCode.ThrowException);
        }

        public int ReadLine(byte[] buffer, SizeExceededActionCode exceededAction)
        {
            int result;
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            lock (this)
            {
                if (this._IsReadActive)
                {
                    throw new InvalidOperationException("读取操作未结束, 不允许多次读取！");
                }
                this._IsReadActive = true;
            }
            try
            {
                int readedCount = 0;
                result = this.ReadLineInternal(buffer, exceededAction, out readedCount);
            }
            finally
            {
                this._IsReadActive = false;
            }
            return result;
        }

        public string ReadLine(Encoding encoding, SizeExceededActionCode exceededAction)
        {
            if (encoding == null)
            {
                throw new ArgumentNullException("encoding");
            }
            int readedCount = this.ReadLine(this._LineBuffer, exceededAction);
            if (readedCount == -1)
            {
                return null;
            }
            return encoding.GetString(this._LineBuffer, 0, readedCount);
        }

        public int ReadLineInternal(byte[] buffer, SizeExceededActionCode exceededAction, out int readedCount)
        {
            readedCount = 0;
            int bufferSize = buffer.Length;
            int posInBuffer = 0;
            int currentByte = 0;
            if (!this._IsReadBuffered)
            {
                while (true)
                {
                    do
                    {
                        currentByte = this._Stream.ReadByte();
                        if (currentByte == -1)
                        {
                            goto Label_00E0;
                        }
                        readedCount++;
                        if (currentByte == 10)
                        {
                            goto Label_00E0;
                        }
                    }
                    while (currentByte == 13);
                    if (readedCount > bufferSize)
                    {
                        if (exceededAction == SizeExceededActionCode.ThrowException)
                        {
                            throw new Exception("行大小超出最大允许值");
                        }
                    }
                    else
                    {
                        buffer[posInBuffer] = (byte)currentByte;
                        posInBuffer++;
                    }
                }
            }
        Label_0016:
            if (this._ReadBufferOffset >= this._ReadBufferEndPos)
            {
                this._ReadBufferEndPos = this._Stream.Read(this._ReadBuffer, 0, 0x7d00);
                this._ReadBufferOffset = 0;
                if (this._ReadBufferEndPos == 0)
                {
                    goto Label_00E0;
                }
            }
            currentByte = this._ReadBuffer[this._ReadBufferOffset];
            this._ReadBufferOffset++;
            readedCount++;
            switch (currentByte)
            {
                case 10:
                    goto Label_00E0;

                case 13:
                    goto Label_0016;

                default:
                    if (readedCount > bufferSize)
                    {
                        if (exceededAction == SizeExceededActionCode.ThrowException)
                        {
                            throw new Exception("行大小超出最大允许值");
                        }
                    }
                    else
                    {
                        buffer[posInBuffer] = (byte)currentByte;
                        posInBuffer++;
                    }
                    goto Label_0016;
            }
        Label_00E0:
            if (readedCount == 0)
            {
                return -1;
            }
            if (readedCount > this._MaxLineSize)
            {
                throw new Exception("行大小超出最大允许值");
            }
            return posInBuffer;
        }

        public int ReadPeriodTerminated(Stream storeStream, int maxSize, SizeExceededActionCode exceededAction)
        {
            int result;
            if (storeStream == null)
            {
                throw new ArgumentNullException("storeStream");
            }
            lock (this)
            {
                if (this._IsReadActive)
                {
                    throw new InvalidOperationException("读取操作未结束, 不允许多次读取！");
                }
                this._IsReadActive = true;
            }
            try
            {
                BufferedStream bufferedStoreStream = new BufferedStream(storeStream, 0x7d00);
                bool lineSizeExceeded = false;
                bool isPeriodTerminated = false;
                int totalReadedCount = 0;
                int readedCount = 0;
                int rawReadedCount = 0;
                if (exceededAction == SizeExceededActionCode.ThrowException)
                {
                    try
                    {
                        readedCount = this.ReadLineInternal(this._LineBuffer, SizeExceededActionCode.JunkAndThrowException, out rawReadedCount);
                    }
                    catch (Exception objExp)
                    {
                        ExceptionHelper.Handle(objExp);
                        lineSizeExceeded = true;
                    }
                    while (rawReadedCount != 0)
                    {
                        totalReadedCount += rawReadedCount;
                        if ((readedCount == 1) && (this._LineBuffer[0] == 0x2e))
                        {
                            isPeriodTerminated = true;
                            break;
                        }
                        if (this._LineBuffer[0] == 0x2e)
                        {
                            if (!lineSizeExceeded && (totalReadedCount <= maxSize))
                            {
                                bufferedStoreStream.Write(this._LineBuffer, 1, readedCount - 1);
                                bufferedStoreStream.Write(this._LineBreak, 0, this._LineBreak.Length);
                            }
                        }
                        else if (!lineSizeExceeded && (totalReadedCount <= maxSize))
                        {
                            bufferedStoreStream.Write(this._LineBuffer, 0, readedCount);
                            bufferedStoreStream.Write(this._LineBreak, 0, this._LineBreak.Length);
                        }
                        try
                        {
                            readedCount = this.ReadLineInternal(this._LineBuffer, SizeExceededActionCode.JunkAndThrowException, out rawReadedCount);
                        }
                        catch (Exception objExp)
                        {
                            ExceptionHelper.Handle(objExp);
                            lineSizeExceeded = true;
                        }
                    }
                }
                else
                {
                    for (readedCount = this.ReadLineInternal(this._LineBuffer, SizeExceededActionCode.JunkAndThrowException, out rawReadedCount); rawReadedCount != 0; readedCount = this.ReadLineInternal(this._LineBuffer, SizeExceededActionCode.JunkAndThrowException, out rawReadedCount))
                    {
                        totalReadedCount += rawReadedCount;
                        if ((readedCount == 1) && (this._LineBuffer[0] == 0x2e))
                        {
                            isPeriodTerminated = true;
                            break;
                        }
                        if (this._LineBuffer[0] == 0x2e)
                        {
                            if (totalReadedCount > maxSize)
                            {
                                throw new Exception("数据大小超出最大允许值");
                            }
                            bufferedStoreStream.Write(this._LineBuffer, 1, readedCount - 1);
                            bufferedStoreStream.Write(this._LineBreak, 0, this._LineBreak.Length);
                        }
                        else
                        {
                            if (totalReadedCount > maxSize)
                            {
                                throw new Exception("数据大小超出最大允许值");
                            }
                            bufferedStoreStream.Write(this._LineBuffer, 0, readedCount);
                            bufferedStoreStream.Write(this._LineBreak, 0, this._LineBreak.Length);
                        }
                    }
                }
                bufferedStoreStream.Flush();
                if (lineSizeExceeded)
                {
                    throw new Exception("行大小超出最大允许值");
                }
                if (!isPeriodTerminated)
                {
                    throw new Exception("已读取到流的结整，段落还未结束！");
                }
                if (totalReadedCount > maxSize)
                {
                    throw new Exception("数据大小超出最大允许值");
                }
                result = totalReadedCount;
            }
            finally
            {
                this._IsReadActive = false;
            }
            return result;
        }

        // Properties
        public bool IsReadBuffered
        {
            get
            {
                return this._IsReadBuffered;
            }
        }

        public int MaximumLineSize
        {
            get
            {
                return this._MaxLineSize;
            }
        }

        public Stream Stream
        {
            get
            {
                return this._Stream;
            }
        }
    }


}
